package com.lagou.boot;

import com.lagou.annotations.LagouRpcFunc;
import com.lagou.annotations.LagouService;
import com.lagou.handler.Handler;
import com.lagou.service.UserServiceImpl;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ServerBoot {


    public static Map<String, Object> SERVICE_MAP = new HashMap<>();

    public static Map<String, Handler> HANDLER_MAPPING = new HashMap<>();
    // 缓存扫描到的类的全限定类名
    private static List<String> CLASS_NAMES = new ArrayList<>();


    public static void main(String[] args) throws InterruptedException {


        doScan("com.lagou");

        doInstance();

        initHandlerMapping();
        //启动服务器
        UserServiceImpl.startServer("127.0.0.1", 8999);
    }


    // 扫描类
    // scanPackage: com.lagou.demo  package---->  磁盘上的文件夹（File）  com/lagou/demo
    private static void doScan(String scanPackage) {
        String scanPackagePath = "/Users/yangkailan/work/01.code/logoulearn/Java_L2_2020.05.21/02_讲义及源码/第三阶段/分布式理论、架构设计（自定义RPC）/code/code/rpc-provider/target/classes/"+ scanPackage.replaceAll("\\.", "/");
        File pack = new File(scanPackagePath);

        File[] files = pack.listFiles();

        for (File file : files) {
            if (file.isDirectory()) { // 子package
                // 递归
                doScan(scanPackage + "." + file.getName());  // com.lagou.demo.controller
            } else if (file.getName().endsWith(".class")) {
                String className = scanPackage + "." + file.getName().replaceAll(".class", "");
                CLASS_NAMES.add(className);
            }

        }


    }

    // ioc容器
    // 基于classNames缓存的类的全限定类名，以及反射技术，完成对象创建和管理
    private static void doInstance() {

        if (CLASS_NAMES.size() == 0) {
            return;
        }
        try {

            for (int i = 0; i < CLASS_NAMES.size(); i++) {
                String className = CLASS_NAMES.get(i);  // com.lagou.demo.controller.DemoController

                // 反射
                Class<?> aClass = Class.forName(className);
                // 区分controller，区分service'
                if (aClass.isAnnotationPresent(LagouService.class)) {
                    LagouService annotation = aClass.getAnnotation(LagouService.class);
                    //获取注解value值
                    String beanName = annotation.value();

                    // 如果指定了id，就以指定的为准
                    if (!"".equals(beanName.trim())) {
                        SERVICE_MAP.put(beanName, aClass.newInstance());
                    } else {
                        // 如果没有指定，就以类名首字母小写
                        beanName = lowerFirst(aClass.getSimpleName());
                        SERVICE_MAP.put(beanName, aClass.newInstance());
                    }
                    // service层往往是有接口的，面向接口开发，此时再以接口名为id，放入一份对象到ioc中，便于后期根据接口类型注入
                    Class<?>[] interfaces = aClass.getInterfaces();
                    for (int j = 0; j < interfaces.length; j++) {
                        Class<?> anInterface = interfaces[j];
                        // 以接口的全限定类名作为id放入
                        SERVICE_MAP.put(anInterface.getName(), aClass.newInstance());
                    }
                } else {
                    continue;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }


    // 首字母小写方法
    public static String lowerFirst(String str) {
        char[] chars = str.toCharArray();
        if ('A' <= chars[0] && chars[0] <= 'Z') {
            chars[0] += 32;
        }
        return String.valueOf(chars);
    }


    /*
        构造一个HandlerMapping处理器映射器
        最关键的环节
        目的：将url和method建立关联
     */
    private static void initHandlerMapping() {
        if (SERVICE_MAP.isEmpty()) {
            return;
        }

        for (Map.Entry<String, Object> entry : SERVICE_MAP.entrySet()) {
            // 获取ioc中当前遍历的对象的class类型
            Class<?> aClass = entry.getValue().getClass();

            if (!aClass.isAnnotationPresent(LagouService.class)) {
                continue;
            }

            String requestId = "";
            if (aClass.isAnnotationPresent(LagouService.class)) {
                LagouService annotation = aClass.getAnnotation(LagouService.class);
                requestId = annotation.value();
            }
            // 获取方法
            Method[] methods = aClass.getMethods();
            for (int i = 0; i < methods.length; i++) {


                Method method = methods[i];

                if(!method.isAnnotationPresent(LagouRpcFunc.class)){
                    continue;
                }
                LagouRpcFunc lagouRpcFunc = method.getAnnotation(LagouRpcFunc.class);
                requestId = requestId + "#" +lagouRpcFunc.value();


                // 把method所有信息及url封装为一个Handler
                Handler handler = new Handler(entry.getValue(), method);


                // 计算方法的参数位置信息
                Parameter[] parameters = method.getParameters();
                for (int j = 0; j < parameters.length; j++) {
                    Parameter parameter = parameters[j];
                    handler.getParamIndexMapping().put(parameter.getName(), j);
                }
                // 建立url和method之间的映射关系（map缓存起来）
                HANDLER_MAPPING.putIfAbsent(requestId, handler);
            }
        }

    }
}
